package com.br4mmie.asciistory.battle;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;

import com.br4mmie.asciistory.FileGetter;

/**
 * Scripted Action class
 * @author Niels
 * Scripted action contains and action and flags determining when this ability is allowed
 */
public class ScriptedAction {
	
	private EncounterAction action; //Action this script is for
	
	/*
	 * The requirements the battle has to meet befre the action may be cast
	 */
	private double minOwnHPperct;
	private double maxOwnHPperct;
	private double minAllyHPperct;
	private double maxAllyHPperct;
	private double minTargetHPperct;
	private double maxTargetHPperct;
	
	private int    minOwnHPval;
	private int    maxOwnHPval;
	private int    minAllyHPval;
	private int    maxAllyHPval;
	private int    minTargetHPval;
	private int    maxTargetHPval;
	
	private int    minOwnHPLost;
	private int    maxOwnHPLost;
	private int    minAllyHPLost;
	private int    maxAllyHPLost;
	private int    minTargetHPLost;
	private int    maxTargetHPLost;
	
	private boolean triggerOnDeath; //This ability is cast when the creature dies

	
	/**
	 * Constructo	
	 * @param filename File to load from
	 */
	public ScriptedAction(String filename)
	{	
		/*
		 * Make all requirements initially true
		 */
		minOwnHPperct = -1;
		maxOwnHPperct = -1;
		minAllyHPperct = -1;
		maxAllyHPperct = -1;
		minTargetHPperct = -1;
		maxTargetHPperct = -1;
		
		minOwnHPval = 1; //creature needs to be alive to be allowed to cast
		maxOwnHPval = -1;
		minAllyHPval = -1;
		maxAllyHPval = -1;
		minTargetHPval = -1;
		maxTargetHPval = -1;
		
		minOwnHPLost = -1;
		maxOwnHPLost = -1;
		minAllyHPLost = -1;
		maxAllyHPLost = -1;
		minTargetHPLost = -1;
		maxTargetHPLost = -1;
		
		triggerOnDeath = false;
		
		String actfile = loadFromFile(filename); //load the action from file and get the file containing the action
		action = new EncounterAction(actfile); 
	}
	
	/**
	 * Load from file function, does the actual loading
	 * Parameters can be given in file in any order, and not all need to be given
	 * @param filename File to load the ScriptedAction from
	 * @return returns String containing the filename for the action
	 * 
	 */
	private String loadFromFile(String filename) 
	{
		BufferedReader in;
		String actfile = "";
		String line = "";
		try
		{
    		in = new BufferedReader(new FileReader(FileGetter.getFilename(filename)));
    		actfile = in.readLine();
    		while ((line = in.readLine())!= null)
    		{
    			line = line.toUpperCase();
    			if(line.equals("TRIGGERONDEATH"))triggerOnDeath = true;
    			else if(line.contains("MINOWNHPPERCT"))minOwnHPperct = Double.parseDouble(line.substring(line.indexOf(" ")+1));
    			else if(line.contains("MAXOWNHPPERCT"))maxOwnHPperct = Double.parseDouble(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MINALLYHPPERCT"))minAllyHPperct = Double.parseDouble(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXALLYHPPERCT"))maxAllyHPperct = Double.parseDouble(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MINTARGETHPPERCT"))minTargetHPperct = Double.parseDouble(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXTARGETHPPERCT"))maxTargetHPperct = Double.parseDouble(line.substring(line.indexOf(" ")+1));
        		
        		else if(line.contains("MINOWNHPVAL"))minOwnHPval = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXOWNHPVAL"))maxOwnHPval = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MINALLYHPVAL"))minAllyHPval = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXALLYHPVAL"))maxAllyHPval = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MINTARGETHPVAL"))minTargetHPval = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXTARGETHPVAL"))maxTargetHPval = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		
        		else if(line.contains("MINOWNHPLOST"))minOwnHPLost = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXOWNHPLOST"))maxOwnHPLost = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MINALLYHPLOST"))minAllyHPLost = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXALLYHPLOST"))maxAllyHPLost = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MINTARGETHPLOST"))minTargetHPLost = Integer.parseInt(line.substring(line.indexOf(" ")+1));
        		else if(line.contains("MAXTARGETHPLOST"))maxTargetHPLost = Integer.parseInt(line.substring(line.indexOf(" ")+1));
    		}
    		in.close();
		}
		catch(FileNotFoundException e)
		{
			System.out.println("File not found " + filename);
		}
		catch(Exception e)
		{
			System.out.println("BLUH in ScriptedAction");
		}
		return actfile;
	}

	/**
	 * Act function, checks if all requirements are true, and casts if so
	 * @param b battle the ability is cast in
	 * @param caster creature trying to cast this ability
	 * @return true if ability was cast, false if ability wasn't cast
	 */
	public boolean act(Battle b, Enemy caster)
	{
		ArrayList <Enemy> allies = new ArrayList<Enemy>();
		
		allies.clear();
		allies.addAll(b.getEnemies());
		allies.remove(caster);
		
		if (checkAbility(allies, caster, b.getPlayer()))
		{	
			action.act(b, caster);
			return true;
		}	

		return false;
	}
	
	/**
	 * checkAbility, Checks all requirements, and returns outcome 
	 * @param allies the casters allies, derived from battle
	 * @param caster the Caster
	 * @param player the Players' representation in battle
	 * @return true if all requirements are met, false otherwise
	 */
	private boolean checkAbility(ArrayList<Enemy> allies, Enemy caster, EncounterPlayer player)
	{
		//Dit is mooier, geen massa's aan if statements.
		//Beetje mooier misschien, Maar wel TRAGER!!!!!!
		//Dit moet ook werken toch?
		//boolean ability = true;
		if(
		checkMinOwnHPperct(caster)
		&& checkMaxOwnHPperct(caster)
		&& checkMinAllyHPperct(allies)
		&& checkMaxAllyHPperct(allies)
		&& checkMinTargetHPperct(player)
		&& checkMaxTargetHPperct(player)
		
		&& checkMinOwnHPval(caster)
		&& checkMaxOwnHPval(caster)
		&& checkMinAllyHPval(allies)
		&& checkMaxAllyHPval(allies)
		&& checkMinTargetHPval(player)
		&& checkMaxTargetHPval(player)
		
		&& checkMinOwnHPLost(caster)
		&& checkMaxOwnHPLost(caster)
		&& checkMinAllyHPLost(allies)
		&& checkMaxAllyHPLost(allies)
		&& checkMinTargetHPLost(player)
		&& checkMaxTargetHPLost(player)
		&& !checktriggerOnDeath(caster)
		)return true;
		else return false;
		//return ability;
	}
	
	/*
	 * Checkers for individual requirements
	 */
	
	private boolean checkMinOwnHPperct(Enemy caster){
		if(minOwnHPperct == -1)return true;
		double perct = caster.getCurrentHP()/caster.getMaxHP();
		return (perct >= minOwnHPperct);
	}
	private boolean checkMaxOwnHPperct(Enemy caster){
		if(maxOwnHPperct == -1)return true;
		double perct = caster.getCurrentHP()/caster.getMaxHP();
		return (perct <= maxOwnHPperct);
	}
	private boolean checkMinAllyHPperct(ArrayList<Enemy> allies)
	{
		if (minAllyHPperct == -1) return true;
		for(Enemy e: allies)
		{
			double perct = e.getCurrentHP()/e.getMaxHP();
			if (perct >= minAllyHPperct) return true;
		}
		return false;
	}
	private boolean checkMaxAllyHPperct(ArrayList<Enemy> allies)
	{
		if (maxAllyHPperct == -1) return true;
		for(Enemy e: allies)
		{
			double perct = e.getCurrentHP()/e.getMaxHP();
			if (perct <= maxAllyHPperct) return true;
		}
		return false;
	}
	private boolean checkMinTargetHPperct(EncounterPlayer player)
	{
		if (minTargetHPperct == -1) return true;
		double perct = player.getCurrentHP()/player.getMaxHP();
		return (perct >= minTargetHPperct);
	}
	private boolean checkMaxTargetHPperct(EncounterPlayer player)
	{
		if (maxTargetHPperct == -1) return true;
		double perct = player.getCurrentHP()/player.getMaxHP();
		return (perct <= maxTargetHPperct);
	}
	
	private boolean checkMinOwnHPval(Enemy caster)
	{
		if (minOwnHPval == -1) return true;
		if (minOwnHPval <= caster.getCurrentHP()) return true;
		
		return false;
	}
	private boolean checkMaxOwnHPval(Enemy caster)
	{
		if (maxOwnHPval == -1) return true;
		if (maxOwnHPval >= caster.getCurrentHP()) return true;
		
		return false;
	}
	private boolean checkMinAllyHPval(ArrayList<Enemy> allies)
	{
		if (minAllyHPval == -1) return true;
		
		for(Enemy e: allies)
		{
			if (minAllyHPval <= e.getCurrentHP()) return true;
		}
		
		return false;
	}
	private boolean checkMaxAllyHPval(ArrayList<Enemy> allies)
	{
		if (maxAllyHPval == -1) return true;
		for(Enemy e: allies)
		{
			if (maxAllyHPval >= e.getCurrentHP()) return true;
		}
		return false;
	}
	private boolean checkMinTargetHPval(EncounterPlayer player)
	{
		if (minTargetHPval == -1) return true;
		if (minTargetHPval <= player.getCurrentHP())return true;
		
		return false;
	}
	private boolean checkMaxTargetHPval(EncounterPlayer player)
	{
		if (maxTargetHPval == -1) return true;
		if (maxTargetHPval >= player.getCurrentHP()) return true;
		
		return false;
	}
	private boolean checkMinOwnHPLost(Enemy caster)
	{
		if (minOwnHPLost == -1) return true;
		if (minOwnHPLost <= caster.getMaxHP()-caster.getCurrentHP()) return true;
		
		return false;
	}
	private boolean checkMaxOwnHPLost(Enemy caster)
	{
		if (maxOwnHPLost == -1) return true;
		if (maxOwnHPLost >= caster.getMaxHP()-caster.getCurrentHP()) return true;
		
		return false;
	}
	private boolean checkMinAllyHPLost(ArrayList<Enemy> allies)
	{
		if (minAllyHPLost == -1) return true;
		for(Enemy e: allies)
		{
			if (minAllyHPLost <= e.getMaxHP()-e.getCurrentHP()) return true;
		}
		
		return false;
	}
	private boolean checkMaxAllyHPLost(ArrayList<Enemy> allies)
	{
		if (maxAllyHPLost == -1) return true;
		for(Enemy e: allies)
		{
			if (maxAllyHPLost >= e.getMaxHP()-e.getCurrentHP()) return true;
		}
		
		return false;
	}
	private boolean checkMinTargetHPLost(EncounterPlayer player)
	{
		if (minTargetHPLost == -1) return true;
		if (minTargetHPLost <= player.getMaxHP()-player.getCurrentHP()) return true;
		
		return false;
	}
	private boolean checkMaxTargetHPLost(EncounterPlayer player)
	{
		if (maxTargetHPLost == -1) return true;
		if (maxTargetHPLost >= player.getMaxHP()-player.getCurrentHP()) return true;
		
		return false;
	}
	
	private boolean checktriggerOnDeath(Enemy caster)
	{
		if ((caster.getCurrentHP() <= 0)&&(triggerOnDeath)) return true;
		
		return false;
	}
}
